#pragma once

#include "config.h"
#include "spinlock.h"

template <typename T, typename Sequence = std::deque<T> >
class ThreadSafeFastQueue
{
public:
	bool IsEmpty() const    { return _c.empty(); }
	size_t Size() const     { return _c.size(); }

	void EnqueueUniquely(const T &x)
	{
		_spinlock.Lock();
		if (find_if(_c.begin(), _c.end(), std::bind2nd(std::equal_to<T>(), x)) == _c.end())
			_c.push_back(x);
		_spinlock.Unlock();
	}


	void Enqueue(const T &x)
	{
		_spinlock.Lock();
		_c.push_back(x);
		_spinlock.Unlock();
	}


	int Dequeue(T &x)
	{
		int rc = -1;
		_spinlock.Lock();
		if (!_c.empty())
		{
			x = _c.front();
			_c.pop_front();
			rc = 0;
		}
		_spinlock.Unlock();
		return rc;
	}


	int Front(T &x)
	{
		int rc = -1;
		_spinlock.Lock();
		if (!_c.empty())
		{
			x = _c.front();
			rc = 0;
		}
		_spinlock.Unlock();
		return rc;
	}


	int TryEnqueue(const T &x)
	{
		int rc;
		if ( (rc = _spinlock.TryLock()) == 0)
		{
			_spinlock.Lock();
			_c.push_back(x);
			_spinlock.Unlock();
		}
		return rc;
	}


	int TryDequeue(T &x)
	{
		int rc;
		if ( (rc = _spinlock.TryLock()) == 0)
		{
			x = _c.front();
			_c.pop_front();
			_spinlock.Unlock();
		}
		return rc;
	}

private:
	Sequence _c;
	Spinlock _spinlock;
};
